import moment from 'moment';
import type default_config from './hexo/default_config';
import type i18n from 'hexo-i18n';
import type Query from 'warehouse/dist/query';
import type css from './plugins/helper/css';
import type { date, date_xml, time, full_date, relative_date, time_tag, moment as _moment } from './plugins/helper/date';
import type { inspectObject, log } from './plugins/helper/debug';
import type favicon_tag from './plugins/helper/favicon_tag';
import type feed_tag from './plugins/helper/feed_tag';
import type { titlecase, word_wrap, truncate, stripHTML, escapeHTML } from './plugins/helper/format';
import type fragment_cache from './plugins/helper/fragment_cache';
import type full_url_for from './plugins/helper/full_url_for';
import type gravatar from './plugins/helper/gravatar';
import type image_tag from './plugins/helper/image_tag';
import type { current, home, home_first_page, post, page, archive, year, month, category, tag } from './plugins/helper/is';
import type js from './plugins/helper/js';
import type link_to from './plugins/helper/link_to';
import type list_archives from './plugins/helper/list_archives';
import type list_categories from './plugins/helper/list_categories';
import type list_posts from './plugins/helper/list_posts';
import type list_tags from './plugins/helper/list_tags';
import type mail_to from './plugins/helper/mail_to';
import type markdown from './plugins/helper/markdown';
import type meta_generator from './plugins/helper/meta_generator';
import type number_format from './plugins/helper/number_format';
import type open_graph from './plugins/helper/open_graph';
import type paginator from './plugins/helper/paginator';
import type relative_url from './plugins/helper/relative_url';
import type render from './plugins/helper/render';
import type search_form from './plugins/helper/search_form';
import type tag_cloud from './plugins/helper/tagcloud';
import type toc from './plugins/helper/toc';
import type url_for from './plugins/helper/url_for';

export type NodeJSLikeCallback<R, E = any> = (err: E, result?: R) => void

export interface RenderData {
  engine?: string;
  content?: string;
  disableNunjucks?: boolean;
  markdown?: any;
  source?: string;
  titlecase?: boolean;
  title?: string;
  excerpt?: string;
  more?: string;
}

// Schema
export interface TagSchema {
  id?: string;
  _id?: string;
  name: string;
  slug: string;
  path: string;
  permalink: string;
  posts: any;
  length: number;
}

export interface DataSchema {
  id?: string;
  data: any;
}

export interface CategorySchema {
  id?: string;
  _id?: string;
  name: string;
  parent?: string;
  slug: string;
  path: string;
  permalink: string;
  posts: any;
  length: number;
}

export interface PostCategorySchema {
  _id?: string;
  post_id: string;
  category_id: string;
}

export interface PostTagSchema {
  _id?: string;
  post_id: string;
  tag_id: string;
}

export interface PostAssetSchema {
  _id: string;
  slug: string;
  modified: boolean;
  post: string;
  renderable: boolean;
  path: string;
  source: string;
}

export interface BasePagePostSchema {

  /**
   * ID generated by warehouse
   */
  _id?: string;

  /**
   * Article title
   */
  title: string;

  /**
   * 	Article created date
   */
  date: moment.Moment,

  /**
   * Article last updated date
   */
  updated: moment.Moment,

  /**
   * 	Comment enabled or not
   */
  comments: boolean;

  /**
   * 	Layout name
   */
  layout: string | false;

  /**
   * The full processed content of the article
   */
  _content: string;

  /**
   * The full processed content of the article
   */
  content?: string;

  /**
   * The path of the source file
   */
  source: string;

  /**
   * The URL of the article without root URL.
   * We usually use url_for(page.path) in theme.
   */
  path: string;

  /**
   * The raw data of the article
   */
  raw: string;

  /**
   * Article excerpt
   */
  excerpt?: string;

  /**
   * Contents except article excerpt
   */
  more?: string;

  /**
   * Full path of the source file
   */
  full_source: string;

  /**
   * Full (encoded) URL of the article
   */
  permalink: string;

  /**
   * The photos of the article (Used in gallery posts)
   */
  photos?: string[];

  /**
   * The external link of the article (Used in link posts)
   */
  link?: string;

  /**
   * The language of the article
   */
  lang?: string;

  /**
   * The language of the article
   */
  language?: string;

  /**
   * Base URL
   */
  base?: string;

  /**
   * Whether the page is a page
   */
  __page?: boolean;

  /**
   * Whether the page is a post
   */
  __post?: boolean;

  /**
   * Whether the page is a home page
   */
  __index?: boolean;

  /**
   * custom variables set in front-matter.
   */
  [key: string]: any;
}

export interface PostSchema extends BasePagePostSchema {

  /**
   * Post ID
   */
  id?: string;

  /**
   * The slug of the post
   */
  slug: string;

  /**
   * True if the post is not a draft
   */
  published: boolean;

  /**
   * The path of the asset directory
   */
  asset_dir: string;

  /**
   * All categories of the post
   */
  categories: Query<CategorySchema>;

  /**
   * All tags of the post
   */
  tags: Query<TagSchema>;

  /**
   * Inner usage
   */
  __permalink?: string;

  /**
   * 	The previous post, `null` if the post is the first post
   */
  prev?: PostSchema | null;

  /**
   * 	The next post, `null` if the post is the last post
   */
  next?: PostSchema | null;

  notPublished: () => boolean;
  setTags: (tags: string[]) => any;
  setCategories: (cats: (string | string[])[]) => any;
}

export interface PageSchema extends BasePagePostSchema {

  /**
   * Posts displayed per page, only available on home page
   */
  per_page?: number;

  /**
   * Total number of pages, only available on home page
   */
  total?: number;

  /**
   * 	Current page number, only available on home page
   */
  current?: number;

  /**
   * The URL of current page, only available on home page
   */
  current_url?: string;

  /**
   * Posts in this page, only available on home page
   */
  posts?: any;

  /**
   * Previous page number. `0` if the current page is the first. only available on home page
   */
  prev?: number;

  /**
   * The URL of previous page. `''` if the current page is the first. only available on home page
   */
  prev_link?: string;

  /**
   * Next page number. `0` if the current page is the last. only available on home page
   */
  next?: number;

  /**
   * The URL of next page. `''` if the current page is the last. only available on home page
   */
  next_link?: string;

  /**
   * Equals true, only available on archive page
   */
  archive?: boolean;

  /**
   * Archive year (4-digit), only available on archive page
   */
  year?: number;

  /**
   * Archive month (2-digit without leading zeros), only available on archive page
   */
  month?: number;

  /**
   * Category name, only available on category page
   */
  category?: string;

  /**
   * Tag name, only available on tag page
   */
  tag?: string;
}

export interface AssetSchema {
  _id?: string;
  path: string;
  modified: boolean;
  renderable: boolean;
  source: string;
}

export interface CacheSchema {
  _id: string;
  hash: string;
  modified: number;
}

// Generator return types
export interface BaseGeneratorReturn {

  /**
   * Path not including the prefixing `/`.
   */
  path: string;

  /**
   * Data
   */
  data?: any;

  /**
   * Layout. Specify the layouts for rendering. The value can be a string or an array.
   * If it’s ignored then the route will return `data` directly.
   */
  layout?: string | string[];
}

export interface SiteLocals {

  /**
   * All posts
   */
  posts: Query<PostSchema>;

  /**
   * 	All pages
   */
  pages: Query<PageSchema>;

  /**
   * All categories
   */
  categories: Query<CategorySchema>;

  /**
   * All tags
   */
  tags: Query<TagSchema>;
  data: any;
}

export interface LocalsType {
  // original properties from Locals class
  /**
   * Page specific information and custom variables set in front-matter.
   */
  page: BasePagePostSchema;

  /**
   * Path of current page
   */
  path: string;

  /**
   * Full URL of current page
   */
  url: string;

  /**
   * Site configuration.
   */
  config: typeof default_config;

  /**
   * 	Theme configuration. Inherits from site configuration.
   */
  theme: any;
  layout: string | boolean;

  /**
   * 	Environment variables
   */
  env: any;
  view_dir: string;

  /**
   * Sitewide information.
   */
  site: SiteLocals;
  cache?: boolean;

  // i18n properties from i18nLocalsFilter
  /**
   * https://hexo.io/docs/internationalization#Templates
   */
  __: ReturnType<i18n['__']>;

  /**
   * https://hexo.io/docs/internationalization#Templates
   */
  _p: ReturnType<i18n['_p']>;

  // result after renderer.compile
  body?: string;
  // from _buildLocals
  filename?: string;

  // helper functions from _bindHelpers
  css: typeof css;
  date: typeof date;
  date_xml: typeof date_xml;
  escape_html: typeof escapeHTML;
  favicon_tag: typeof favicon_tag;
  feed_tag: typeof feed_tag;
  fragment_cache: ReturnType<typeof fragment_cache>;
  full_date: typeof full_date;
  full_url_for: typeof full_url_for;
  gravatar: typeof gravatar;
  image_tag: typeof image_tag;
  inspect: typeof inspectObject;
  is_archive: typeof archive;
  is_category: typeof category;
  is_current: typeof current;
  is_home: typeof home;
  is_home_first_page: typeof home_first_page;
  is_month: typeof month;
  is_page: typeof page;
  is_post: typeof post;
  is_tag: typeof tag;
  is_year: typeof year;
  js: typeof js;
  link_to: typeof link_to;
  list_archives: typeof list_archives;
  list_categories: typeof list_categories;
  list_posts: typeof list_posts;
  list_tags: typeof list_tags;
  log: typeof log;
  mail_to: typeof mail_to;
  markdown: typeof markdown;
  meta_generator: typeof meta_generator;
  moment: typeof _moment;
  number_format: typeof number_format;
  open_graph: typeof open_graph;
  paginator: typeof paginator;
  partial: ReturnType<typeof render>;
  relative_date: typeof relative_date;
  relative_url: typeof relative_url;
  render: ReturnType<typeof render>;
  search_form: typeof search_form;
  strip_html: typeof stripHTML;
  tag_cloud: typeof tag_cloud;
  tagcloud: typeof tag_cloud;
  time: typeof time;
  time_tag: typeof time_tag;
  titlecase: typeof titlecase;
  toc: typeof toc;
  trim: typeof stripHTML;
  truncate: typeof truncate;
  url_for: typeof url_for;
  word_wrap: typeof word_wrap;
}

export interface FilterOptions {
  context?: any;
  args?: any[];
}
